﻿using Newtonsoft.Json;
using System;
using System.IO;
using System.Reflection;
using System.Text;
using System.Web;

namespace GrainManage.Server
{
    public enum LogLevel { Fatal, Error, Warn, Info, Debug, All }

    public class LogUtil
    {
        public static void InitialConfig(string configFilePath)
        {
            if (configFilePath.StartsWith("~") || !configFilePath.Contains(":"))
            {
                configFilePath = HttpContext.Current.Server.MapPath(configFilePath);
            }
            log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(configFilePath));
        }

        public static void Write(int skipFrames, LogLevel level, object input, object output, Exception e)
        {
            //index 0:当前方法(GetMethodBase) 1：父级调用方法 2：祖父级调用方法
            var frame = new System.Diagnostics.StackFrame(skipFrames, false);
            var methodBase = frame.GetMethod();
            var message = GenetateMessage(methodBase, e, input, output, System.Web.HttpContext.Current.Request.HttpMethod);
            Write(message, level, e);
        }

        public static void Write(string message, LogLevel level, Exception e)
        {
            var _Logger = log4net.LogManager.GetLogger("GrainManageLogger");
            if (e != null)
            {
                switch (level)
                {
                    case LogLevel.Fatal:
                        _Logger.Fatal(message, e);
                        break;
                    case LogLevel.Error:
                        _Logger.Error(message, e);
                        break;
                    case LogLevel.Warn:
                        _Logger.Warn(message, e);
                        break;
                    case LogLevel.Info:
                        _Logger.Info(message, e);
                        break;
                    case LogLevel.Debug:
                        _Logger.Debug(message, e);
                        break;
                }
            }
            else
            {
                switch (level)
                {
                    case LogLevel.Fatal:
                        _Logger.Fatal(message);
                        break;
                    case LogLevel.Error:
                        _Logger.Error(message);
                        break;
                    case LogLevel.Warn:
                        _Logger.Warn(message);
                        break;
                    case LogLevel.Info:
                        _Logger.Info(message);
                        break;
                    case LogLevel.Debug:
                        _Logger.Debug(message);
                        break;
                }
            }
        }

        private static string GenetateMessage(MethodBase method, Exception e, object input, object output, string requestWay)
        {
            var methodName = method.DeclaringType.FullName + "." + method.Name;
            StringBuilder builder = new StringBuilder();
            builder.AppendLine("Client IP: " + GrainManage.Server.Util.IPUtil.RequestHostAddress);

            if (!string.IsNullOrEmpty(requestWay))
            {
                builder.AppendLine("Request Way: " + requestWay);
            }
            if (!string.IsNullOrEmpty(methodName))
            {
                builder.AppendLine("Method: " + methodName);
            }
            if (input != null)
            {
                builder.AppendLine("Input Parameter:");
                if (input.GetType() == typeof(string))
                {
                    builder.AppendLine(input as string);
                }
                else
                {
                    builder.AppendLine(Serialize(input));
                }
            }
            if (output != null)
            {
                builder.AppendLine("Output Parameter:");

                if (output.GetType() == typeof(string))
                {
                    builder.AppendLine(input as string);
                }
                else
                {
                    builder.AppendLine(Serialize(output));
                }
            }
            if (e != null)
            {

                if (!string.IsNullOrEmpty(e.Message))
                {
                    builder.AppendLine("Message: " + e.Message);
                }
                if (!string.IsNullOrEmpty(e.Source))
                {
                    builder.AppendLine("Source: " + e.Source);
                }
                if (e.TargetSite != null)
                {
                    builder.AppendLine("TargetSite: " + e.TargetSite.DeclaringType.FullName + "." + e.TargetSite.Name);
                }
                if (!string.IsNullOrEmpty(e.StackTrace))
                {
                    builder.AppendLine("StackTrace:");
                    builder.AppendLine(e.StackTrace);
                }
                if (e.InnerException != null && string.IsNullOrEmpty(e.InnerException.Message))
                {
                    builder.AppendLine("InnerException Message: " + e.InnerException.Message);
                }
            }
            return builder.ToString();
        }

        private static string Serialize(object model)
        {
            var result = string.Empty;
            if (model != null)
            {
                if (!(model is string) && !(model is ValueType))
                {
                    result = JsonConvert.SerializeObject(model, Formatting.Indented);
                }
                else
                {
                    result = Convert.ToString(model);
                }
            }
            return result;
        }
    }
}